using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Data;
using System.ComponentModel.Design.Serialization;
using System.Data;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using Telerik.Charting;
using System.Drawing;

namespace Telerik.WinControls.UI.Design
{
    public class ChartDesigner : ControlDesigner, IChartDesigner
    {
        /// <summary>
        /// Action List collection, for action tags menu creation 
        /// </summary>
        private DesignerActionListCollection actionLists;

        /// <summary>
        /// Gets Action List collection
        /// </summary>
        public override DesignerActionListCollection ActionLists
        {
            get
            {
                if (actionLists == null)
                {
                    actionLists = new DesignerActionListCollection();
                    actionLists.Add(new RadChartDesignersActionList(this.radChart));
                }
                return actionLists;
            }
        }

        private RadChart radChart;
        public string tempFileName;
        private IDesignerHost designerHost;
        private IComponentChangeService changeService;

        private void ChartFirstInitialization()
        {
            if (radChart.Series.Count == 0)
            {
                radChart.CreateSeries("Series 1", Color.Empty, Color.Empty, ChartSeriesType.Bar);
                radChart.CreateSeries("Series 2", Color.Empty, Color.Empty, ChartSeriesType.Bar);
            }
        }

        public override void Initialize(IComponent component)
        {
            radChart = (RadChart) component;

            tempFileName = Path.GetTempFileName();
            
            designerHost = null;
            if (component.Site != null)
                designerHost = (IDesignerHost) component.Site.GetService(typeof (IDesignerHost));          
            if (designerHost != null && 
                designerHost.TransactionDescription != "Paste components" && 
                !designerHost.Loading)
            {
                ChartFirstInitialization();
            }

            radChart.Chart.DesignTime = true;
            base.Initialize(component);

            this.changeService = GetService(typeof (IComponentChangeService)) as IComponentChangeService;
            this.changeService.ComponentChanged += new ComponentChangedEventHandler(changeService_ComponentChanged);
        }

        private void changeService_ComponentChanged(object sender, ComponentChangedEventArgs e)
        {
            radChart.UpdateGraphics();
        }

       /// <summary>
        /// Finds DataSource object by name
        /// </summary>
        /// <param name="dataSourceName"></param>
        /// <returns></returns>
        internal object FindDataSource(string dataSourceName)
        {
            foreach (Object component in this.radChart.Site.Container.Components)
            {
                if (String.Compare(TypeDescriptor.GetProperties(component)["Name"].GetValue(component).ToString(), dataSourceName, true) == 0)
                {
                    try
                    {
                        return component;
                    }
                    catch
                    {
                        try
                        {
                            return component;
                        }
                        catch
                        {
                            try
                            {
                                return component;
                            }
                            catch
                            {
                                return null;
                            }
                        }
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Generates new BindingSource name for VS IDE component
        /// </summary>
        /// <param name="dataSource"></param>
        /// <param name="dataMember"></param>
        /// <returns></returns>
        private static string GenerateNewBindingSourceName(object dataSource, string dataMember)
        {
            // DataSet based BindingSources
            if (!String.IsNullOrEmpty(dataMember))
            {
                return dataMember + "BindingSource";
            }

            // Object based BindingSources
            Type type = dataSource as Type;
            if (type == null)
            {
                IComponent component = dataSource as IComponent;
                if (component != null)
                {
                    ISite componentSite = component.Site;
                    if ((componentSite != null) && !String.IsNullOrEmpty(componentSite.Name))
                    {
                        return componentSite.Name + "BindingSource";
                    }
                }
            }
            else
            {
                return type.Name + "BindingSource";
            }

            return "BindingSource";
        }

        /// <summary>
        /// Generates unique component's name
        /// </summary>
        /// <param name="host"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string GetUniqueSiteName(IDesignerHost host, string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return null;
            }
            INameCreationService service = (INameCreationService) host.GetService(typeof (INameCreationService));
            if (service == null)
            {
                return null;
            }
            object obj = host.Container.Components[name];
            if (obj == null)
            {
                if (!service.IsValidName(name))
                {
                    return null;
                }
                return name;
            }
            string text = name;
            for (int i = 1; !service.IsValidName(text); i++)
            {
                text = name + i.ToString(CultureInfo.InvariantCulture);
            }
            return text;
        }

        /// <summary>
        /// Creates new project data source instance
        /// </summary>
        /// <param name="dsDescriptor"></param>
        /// <returns></returns>
        private object GetNewProjectDataSourceInstance(DataSourceDescriptor dsDescriptor)
        {
            DataSourceProviderService dsps = base.GetService(typeof (DataSourceProviderService)) as DataSourceProviderService;
            designerHost = base.GetService(typeof (IDesignerHost)) as IDesignerHost;

            Type type = Type.GetType(dsDescriptor.TypeName, true, true);
            if (!dsDescriptor.IsDesignable)
            {
                return type;
            }

            foreach (IComponent component in designerHost.Container.Components)
            {
                if (type.Equals(component.GetType()))
                {
                    return component;
                }
            }

            object obj = null;
            try
            {
                if (dsps != null) obj = dsps.AddDataSourceInstance(designerHost, dsDescriptor);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                obj = null;
            }

            return obj;
        }

        /// <summary>
        /// Creates new BindingSource
        /// </summary>
        /// <param name="dsDescriptor"></param>
        /// <param name="dataMember"></param>
        /// <returns></returns>
        private BindingSource CreateNewBindingSource(DataSourceDescriptor dsDescriptor, string dataMember)
        {
            DataSourceProviderService dsps = base.GetService(typeof (DataSourceProviderService)) as DataSourceProviderService;
            designerHost = base.GetService(typeof (IDesignerHost)) as IDesignerHost;

            if ((designerHost == null) || (dsps == null))
            {
                return null;
            }

            object dataSource = GetNewProjectDataSourceInstance(dsDescriptor);
            if (dataSource == null)
            {
                return null;
            }

            // Try to get DataMember from DataSet-based DataSource
            if (dataSource is DataSet)
            {
                DataSet ds = dataSource as DataSet;

                if (ds.Tables.Count == 1)
                {
                    dataMember = ds.Tables[0].TableName;
                }
            }

            BindingSource bs = new BindingSource(dataSource, dataMember);
            string name = GetUniqueSiteName(designerHost, GenerateNewBindingSourceName(dataSource, dataMember));
            DesignerTransaction designerTransaction = designerHost.CreateTransaction("BindingSourceCreate");
            try
            {
                try
                {
                    // Add BindingSource component
                    designerHost.Container.Add(bs, name);
                }
                catch (Exception ex)
                {
                    if (designerTransaction != null)
                    {
                        designerTransaction.Cancel();
                    }
                    MessageBox.Show(ex.Message);
                    return null;
                }

                dsps.NotifyDataSourceComponentAdded(bs);

                if (designerTransaction != null)
                {
                    designerTransaction.Commit();
                    designerTransaction = null;
                }
            }
            finally
            {
                if (designerTransaction != null)
                {
                    designerTransaction.Cancel();
                }
            }
            return bs;
        }

        /// <summary>
        /// Invokes standard new project data source creation dialog
        /// </summary>
        /// <returns></returns>
        internal string AddNewDataSource()
        {
            string bsName = string.Empty;
            try
            {
                DataSourceProviderService dsps = base.GetService(typeof (DataSourceProviderService)) as DataSourceProviderService;
                IDesignerHost dhost = base.GetService(typeof (IDesignerHost)) as IDesignerHost;
                if ((dsps != null) && (dhost != null))
                {
                    DataSourceGroup dsGroup = dsps.InvokeAddNewDataSource(this.radChart, FormStartPosition.CenterScreen);
                    if (dsGroup != null)
                    {
                        foreach (DataSourceDescriptor dsDescriptor in dsGroup.DataSources)
                        {
                            BindingSource bs = CreateNewBindingSource(dsDescriptor, String.Empty);
                            this.radChart.DataSource = bs;
                            bsName = dsDescriptor.Name;
                            continue;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            return bsName;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                File.Delete(tempFileName);
                GC.Collect();
            }
        }

        public void RaiseComponentChanged()
        {
            RaiseComponentChanged(null, null, null);
        }

        public void Update()
        {
            radChart.UpdateGraphics();
        }
    }
}